<?php
// +----------------------------------------------------------------------
// | 模型
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace app\model;

use think\Model;
use think\db\Query;

/**
 * 系统菜单模型
 *
 * Class SystemMenusModel
 * @package app\model
 * @OA\Schema(
 *   schema="GetSystemMenus",
 *   type="object",
 *   @OA\Property(description="ID", property="id", type="integer", example=1),
 *   @OA\Property(description="父级ID", property="parentId", type="integer", example=0),
 *   @OA\Property(description="类型", property="type", type="integer", example="menu"),
 *   @OA\Property(description="菜单名称", property="menuName", type="string", example="系统功能"),
 *   @OA\Property(description="标识名称", property="routeName", type="string", example="System"),
 *   @OA\Property(description="路由地址", property="path", type="string", example="/path"),
 *   @OA\Property(description="组件地址", property="component", type="string", example="/component"),
 *   @OA\Property(description="iframe地址", property="frameSrc", type="string", example="/frameSrc"),
 *   @OA\Property(description="路由重定向", property="redirect", type="string", example="/redirect"),
 *   @OA\Property(description="菜单图标", property="icon", type="string", example="icon"),
 *   @OA\Property(description="配置状态", property="options", type="integer", example=11001),
 *   @OA\Property(description="备注", property="remark", type="string", example="备注信息"),
 *   @OA\Property(description="排序", property="sort", type="integer", example=10),
 *   @OA\Property(description="状态", property="status", type="boolean", example=true),
 *   @OA\Property(description="创建时间", property="createTime", type="string", format="date-time", example="2024-01-01T12:00:00Z"),
 *   @OA\Property(description="更新时间", property="updateTime", type="string", format="date-time", example="2024-01-02T12:00:00Z")
 * )
 * @OA\Schema(
 *   schema="SetSystemMenus",
 *   type="object",
 *   @OA\Property(description="父级ID", property="parentId", type="integer", example=0),
 *   @OA\Property(description="类型", property="type", type="integer", example="menu"),
 *   @OA\Property(description="菜单名称", property="menuName", type="string", example="系统功能"),
 *   @OA\Property(description="标识名称", property="routeName", type="string", example="System"),
 *   @OA\Property(description="路由地址", property="path", type="string", example="/path"),
 *   @OA\Property(description="组件地址", property="component", type="string", example="/component"),
 *   @OA\Property(description="iframe地址", property="frameSrc", type="string", example="/frameSrc"),
 *   @OA\Property(description="路由重定向", property="redirect", type="string", example="/redirect"),
 *   @OA\Property(description="菜单图标", property="icon", type="string", example="icon"),
 *   @OA\Property(description="配置状态", property="options", type="integer", example=11001),
 *   @OA\Property(description="备注", property="remark", type="string", example="备注信息"),
 *   @OA\Property(description="排序", property="sort", type="integer", example=10),
 *   @OA\Property(description="状态", property="status", type="boolean", example=true)
 * )
 */
class SystemMenusModel extends Model
{
    // 设置表名
    protected $name = 'system_menus';
    // 设置字段信息
    protected $schema = [
        'id'          => 'int',
        'parent_id'   => 'int',
        // 类型（menu、iframe、link、button）
        'type'        => 'string',
        // 菜单名称
        'menu_name'   => 'string',
        // 标识名称
        'route_name'  => 'string',
        // 路由地址
        'path'        => 'string',
        // 组件地址
        'component'   => 'string',
        // frame地址
        'frame_src'   => 'string',
        // 路由重定向
        'redirect'    => 'string',
        // 菜单图标
        'icon'        => 'string',
        // 配置状态（keepAlive、hiddenTag、fixedTag、showLink、showParent）
        'options'     => 'int',
        // 备注
        'remark'      => 'string',
        // 排序
        'sort'        => 'int',
        // 状态
        'status'      => 'bool',
        // 创建时间
        'create_time' => 'datetime',
        // 更新时间
        'update_time' => 'datetime',
    ];
    // 模型数据不区分大小写
    protected $strict = false;
    // 数据转换为驼峰命名
    protected $convertNameToCamel = true;
    // 移除关联字段
    protected $hidden = ['pivot'];

    // 定义位掩码
    const KEEP_ALIVE_MASK = 1;
    const HIDDEN_TAG_MASK = 2;
    const FIXED_TAG_MASK = 4;
    const SHOW_LINK_MASK = 8;
    const SHOW_PARENT_MASK = 16;

    /**
     * 获取完整数据（包含关联与排序）
     * 
     * @return Query
     */
    static public function queryOrder()
    {
        return self::order([
            'sort' => 'asc',
            'id'   => 'asc'
        ]);
    }

    /**
     * 修改单个状态字段（外部调用）
     *
     * @param string $field
     * @param bool $value
     */
    public function setSingleStatusField($field, $value)
    {
        $options = $this->options;
        switch ($field) {
            case 'keepAlive':
                $options['keepAlive'] = !!$value;
                break;
            case 'hiddenTag':
                $options['hiddenTag'] = !!$value;
                break;
            case 'fixedTag':
                $options['fixedTag'] = !!$value;
                break;
            case 'showLink':
                $options['showLink'] = !!$value;
                break;
            case 'showParent':
                $options['showParent'] = !!$value;
                break;
            default:
                throw new \InvalidArgumentException("Invalid status field: $field");
        }
        $this->options = $options;
    }

    /**
     * 一对多关联 - 子菜单
     * 
     * @return
     */
    public function children()
    {
        return $this->hasMany(SystemMenusModel::class, 'parent_id', 'id');
    }

    /**
     * 搜索器 - 权限
     * 
     * @param Query $query 请求
     * @param mixed $value 字段值
     * @param array $data 完整数据
     * @return
     */
    public function searchPermissionsAttr($query, $value, $data)
    {
        $query->whereIn('route_name', $value);
    }

    /**
     * 搜索器 - 类型
     * 
     * @param Query $query 请求
     * @param mixed $value 字段值
     * @param array $data 完整数据
     * @return
     */
    public function searchTypeAttr($query, $value, $data)
    {
        $query->where('type', $value);
    }

    /**
     * 搜索器 - 菜单名称
     * 
     * @param Query $query 请求
     * @param mixed $value 字段值
     * @param array $data 完整数据
     * @return
     */
    public function searchMenuNameAttr($query, $value, $data)
    {
        $query->where('menu_name', 'like', '%' . $value . '%');
    }

    /**
     * 搜索器 - 标识名称
     * 
     * @param Query $query 请求
     * @param mixed $value 字段值
     * @param array $data 完整数据
     * @return
     */
    public function searchRouteNameAttr($query, $value, $data)
    {
        $query->where('route_name', 'like', '%' . $value . '%');
    }

    /**
     * 搜索器 - 备注
     * 
     * @param Query $query 请求
     * @param mixed $value 字段值
     * @param array $data 完整数据
     * @return
     */
    public function searchRemarkAttr($query, $value, $data)
    {
        $query->where('remark', 'like', '%' . $value . '%');
    }

    /**
     * 搜索器 - 状态
     * 
     * @param Query $query 请求
     * @param mixed $value 字段值
     * @param array $data 完整数据
     * @return
     */
    public function searchStatusAttr($query, $value, $data)
    {
        $query->where('status', !!$value);
    }

    /**
     * 获取器 - 配置状态
     *
     * @param mixed $value
     * @return array
     */
    public function getOptionsAttr($value)
    {
        return [
            'keepAlive' => (bool)($value & self::KEEP_ALIVE_MASK),
            'hiddenTag' => (bool)($value & self::HIDDEN_TAG_MASK),
            'fixedTag' => (bool)($value & self::FIXED_TAG_MASK),
            'showLink' => (bool)($value & self::SHOW_LINK_MASK),
            'showParent' => (bool)($value & self::SHOW_PARENT_MASK),
        ];
    }

    /**
     * 获取器 - 状态
     *
     * @param mixed $value
     * @return array
     */
    public function getStatusAttr($value)
    {
        return !!$value;
    }

    /**
     * 修改器 - 配置状态
     *
     * @param mixed $value
     * @return int
     */
    public function setOptionsAttr($value)
    {
        $options = 0;
        $options |= ($value['keepAlive'] ?? false) ? self::KEEP_ALIVE_MASK : 0;
        $options |= ($value['hiddenTag'] ?? false) ? self::HIDDEN_TAG_MASK : 0;
        $options |= ($value['fixedTag'] ?? false) ? self::FIXED_TAG_MASK : 0;
        $options |= ($value['showLink'] ?? false) ? self::SHOW_LINK_MASK : 0;
        $options |= ($value['showParent'] ?? false) ? self::SHOW_PARENT_MASK : 0;

        return $options;
    }

    /**
     * 修改器 - 状态
     *
     * @param mixed $value
     * @return int
     */
    public function setStatusAttr($value)
    {
        return !!$value;
    }

    /**
     * 删除事件
     * 
     * @param mixed $data 完整数据
     * @return
     */
    public static function onAfterDelete($data)
    {
        SystemMenusModel::destroy(function ($query) use ($data) {
            $query->where('parent_id', $data->id);
        });
    }
}
